/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package GUI;

import java.awt.event.ActionEvent;
import weka.gui.visualize.PrintableComponent;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.ActionListener;
import java.awt.event.InputEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.Serializable;
import java.util.Hashtable;

import javax.swing.BorderFactory;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JViewport;
import javax.swing.ListSelectionModel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.text.JTextComponent;
import org.jfree.chart.ChartPanel;
import weka.core.FastVector;

/**
 *
 * @author kevin
 */
public class ResultHistoryPanel
        extends JPanel {

    /** for serialization */
    static final long serialVersionUID = 4297069440135326829L;
    /** An optional component for single-click display */
    protected JTextComponent m_SingleText;
    /** An lable for AUC display */
    protected JLabel m_AucLabel = new JLabel("AUC(Area under the ROC curve): NO DATA");
    /** A hashtable mapping names to AUC */
    protected Hashtable m_HashAucs = new Hashtable();
    /** A panel that contains the ROC curve */
    protected JPanel m_CurvePanel = new JPanel();
    /** The named result being viewed in the single-click display */
    protected String m_SingleName;
    /** A hashtable mapping names to target class */
    protected Hashtable m_HashClass = new Hashtable();
    /** The list model */
    protected DefaultListModel m_Model = new DefaultListModel();
    /** The list component */
    protected JList m_List = new JList(m_Model);
    /** A Hashtable mapping names to result buffers */
    protected Hashtable m_HashResults = new Hashtable();
    /** A Hashtable mapping names to charts */
    protected Hashtable m_HashCharts = new Hashtable();
    /** A Hashtable mapping names to output text components */
    protected Hashtable m_HashFramedOutput = new Hashtable();
    /** A hashtable mapping names to arbitrary objects */
    protected Hashtable m_HashObjs = new Hashtable();
    /** Let the result history list handle right clicks in the default
    manner---ie, pop up a window displaying the buffer */
    protected boolean m_HandleRightClicks = true;
    /** for printing the output to files */
    protected PrintableComponent m_Printer = null;
    /** To show the detail information of result */
    protected JButton m_DetailButton = new JButton("detail view …");
    /** radiobutton to select target class */
    protected JPanel m_ClassPanel = new JPanel();

    /** a hash table for predictions */
    protected Hashtable m_Predictions = new Hashtable();
    protected int m_CurrentIndex = 0;
    protected Hashtable m_NameIndex = new Hashtable();
    /**
     * Extension of MouseAdapter that implements Serializable.
     */
    public static class RMouseAdapter
            extends MouseAdapter implements Serializable {

        /** for serialization */
        static final long serialVersionUID = -8991922650552358669L;
    }

    /**
     * Extension of KeyAdapter that implements Serializable.
     */
    public static class RKeyAdapter
            extends KeyAdapter implements Serializable {

        /** for serialization */
        static final long serialVersionUID = -8675332541861828079L;
    }

    /**
     * Create the result history object
     *
     * @param text the optional text component for single-click display
     */
    public ResultHistoryPanel(JTextComponent text) {
        FastVector f = new FastVector();
        f = null;
        try {
            ChartFramePanel chartFrame = new ChartFramePanel(f,0);
            m_CurvePanel.add(chartFrame.getPanel());
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        //m_CurvePanel.setSize(400, 300);
        m_SingleText = text;
        if (text != null) {
            m_Printer = new PrintableComponent(m_SingleText);
        }
        m_List.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        m_List.addMouseListener(new RMouseAdapter() {

            private static final long serialVersionUID = -9015397020486290479L;

            @Override
            public void mouseClicked(MouseEvent e) {
                if ((e.getModifiers() & InputEvent.BUTTON1_MASK)
                        == InputEvent.BUTTON1_MASK) {
                    if (((e.getModifiers() & InputEvent.SHIFT_DOWN_MASK) == 0)
                            && ((e.getModifiers() & InputEvent.CTRL_DOWN_MASK) == 0)) {
                        int index = m_List.locationToIndex(e.getPoint());
                        if ((index != -1) && (m_SingleText != null)) {
                            //show different result with the left click
                            String temp = (String) m_Model.elementAt(index);
                            setSingle(temp);
                            setAuc(temp);
                            setChart(temp);
                        }
                    }
                } else {
                    // if there are stored objects then assume that the storer
                    // will handle popping up the text in a seperate frame
                    if (m_HandleRightClicks) {
                        int index = m_List.locationToIndex(e.getPoint());
                        if (index != -1) {
                            String name = (String) m_Model.elementAt(index);
                            openFrame(name);
                        }
                    }
                }
            }
        });

        m_List.addKeyListener(new RKeyAdapter() {

            private static final long serialVersionUID = 7910681776999302344L;

            @Override
            public void keyReleased(KeyEvent e) {
                if (e.getKeyCode() == KeyEvent.VK_DELETE) {
                    int selected = m_List.getSelectedIndex();
                    if (selected != -1) {
                        removeResult((String) m_Model.elementAt(selected));
                    }
                }
            }
        });
        m_List.getSelectionModel().addListSelectionListener(new ListSelectionListener() {

            public void valueChanged(ListSelectionEvent e) {
                if (!e.getValueIsAdjusting()) {
                    ListSelectionModel lm = (ListSelectionModel) e.getSource();
                    for (int i = e.getFirstIndex(); i <= e.getLastIndex(); i++) {
                        if (lm.isSelectedIndex(i)) {
                            //m_AttSummaryPanel.setAttribute(i);
                            if ((i != -1) && (m_SingleText != null)) {
                                setSingle((String) m_Model.elementAt(i));
                            }
                            break;
                        }
                    }
                }
            }
        });

        ////////////////////detail view button/////////////////
        m_DetailButton.addActionListener(new ActionListener(){

            public void actionPerformed(ActionEvent e) {
                JFrame detailPanel = new JFrame("Detail information about the clissified result");
                //detailPanel.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                detailPanel.setSize(700, 700);
                Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
                detailPanel.setLocation(
                        (screenSize.width-detailPanel.getWidth())/2,
                        (screenSize.height-detailPanel.getHeight())/2);
                JScrollPane js = new JScrollPane(m_SingleText);
                //js.add(m_SingleText);
                detailPanel.add(js);
                
                detailPanel.setVisible(true);

            }

        });


        setLayout(new BorderLayout());
        //    setBorder(BorderFactory.createTitledBorder("Result history"));
        final JScrollPane js = new JScrollPane(m_List);
        js.getViewport().addChangeListener(new ChangeListener() {

            private int lastHeight;

            public void stateChanged(ChangeEvent e) {
                JViewport vp = (JViewport) e.getSource();
                int h = vp.getViewSize().height;
                if (h != lastHeight) { // i.e. an addition not just a user scrolling
                    lastHeight = h;
                    int x = h - vp.getExtentSize().height;
                    vp.setViewPosition(new Point(0, x));
                }
            }
        });
        add(js, BorderLayout.CENTER);
    }

    /**
     * Adds a new result to the result list.
     *
     * @param name the name to associate with the result
     * @param result the StringBuffer that contains the result text
     */
    public void addResult(String name, StringBuffer result) {

        m_Model.addElement(name);
        m_HashResults.put(name, result);
    }

    /**
     * Adds a new auc to the aucs list
     *
     * @param name
     * @param auc
     */
    public void addAuc(String name, String auc) {
        m_HashAucs.put(name, auc);
    }

    /**
     * Adds a new chartpanel to the chart list
     * @param name
     * @param chart
     */
    public void addChart(String name, ChartPanel chart) {
        m_HashCharts.put(name, chart);
    }
    public void addClass(String name,String[] targetClass){
        m_HashClass.put(name, targetClass);
    }

    /**
     * Removes one of the result buffers from the history. Any windows currently
     * displaying the contents of the buffer are not affected.
     *
     * @param name the name of the buffer to remove.
     */
    public void removeResult(String name) {

        StringBuffer buff = (StringBuffer) m_HashResults.get(name);
        if (buff != null) {
            m_HashResults.remove(name);
            m_Model.removeElement(name);
            m_HashObjs.remove(name);
            System.gc();
        }
    }

    /**
     * Removes one of the auc buffers from the history
     *
     * @param name
     */
    public void removeAuc(String name) {
        StringBuffer buff = (StringBuffer) m_HashAucs.get(name);
        if (buff != null) {
            m_HashAucs.remove(name);
        }
    }

    /**
     * Removes one of the charts from the history.
     * Any windows currently displaying the contents of the chart are not affected.
     * @param name
     */
    public void removeChart(String name) {
        ChartPanel chart = (ChartPanel) m_HashCharts.get(name);
        if (chart != null) {
            m_HashCharts.remove(name);
        }
    }

    /**
     *
     * @param name
     */
    public void removeAllResult(String name) {

        this.removeAuc(name);
        this.removeChart(name);
        this.removeResult(name);
    }

    /**
     * Removes all of the result buffers from the history. Any windows currently
     * displaying the contents of the buffer are not affected.
     */
    public void clearResults() {
        m_HashResults.clear();
        m_Model.clear();
        m_HashObjs.clear();
        System.gc();
    }

    /**
     * Adds an object to the results list
     * @param name the name to associate with the object
     * @param o the object
     */
    public void addObject(String name, Object o) {
        m_HashObjs.put(name, o);
    }

    /**
     * Get the named object from the list
     * @param name the name of the item to retrieve the stored object
     * for
     * @return the object or null if there is no object at this index
     */
    public Object getNamedObject(String name) {
        Object v = null;
        v = m_HashObjs.get(name);
        return v;
    }

    /**
     * Gets the object associated with the currently
     * selected item in the list.
     * @return the object or null if there is no
     * object corresponding to the current selection in
     * the list
     */
    public Object getSelectedObject() {
        Object v = null;
        int index = m_List.getSelectedIndex();
        if (index != -1) {
            String name = (String) (m_Model.elementAt(index));
            v = m_HashObjs.get(name);
        }

        return v;
    }

    /**
     * Gets the named buffer
     * @param name
     * @return the buffer or null if there are no items in
     * the list
     */
    public StringBuffer getNamedBuffer(String name) {
        StringBuffer b = null;
        b = (StringBuffer) (m_HashResults.get(name));
        return b;
    }

    /**
     * Gets the buffer associated with the currently
     * selected item in the list.
     * @return the buffer or null if there are no items in
     * the list
     */
    public StringBuffer getSelectedBuffer() {
        StringBuffer b = null;
        int index = m_List.getSelectedIndex();
        if (index != -1) {
            String name = (String) (m_Model.elementAt(index));
            b = (StringBuffer) (m_HashResults.get(name));
        }
        return b;
    }

    /**
     * Get the name of the currently selected item in the list
     * @return the name of the currently selected item or null if no
     * item selected
     */
    public String getSelectedName() {
        int index = m_List.getSelectedIndex();
        if (index != -1) {
            return (String) (m_Model.elementAt(index));
        }
        return null;
    }

    /**
     * Gets the name of theitem in the list at the specified index
     * @param index
     * @return the name of item or null if there is no item at that index
     */
    public String getNameAtIndex(int index) {
        if (index != -1) {
            return (String) (m_Model.elementAt(index));
        }
        return null;
    }

    /**
     * Sets the single-click display to view the named result.
     *
     * @param name the name of the result to display.
     */
    public void setSingle(String name) {

        StringBuffer buff = (StringBuffer) m_HashResults.get(name);
        if (buff != null) {
            m_SingleName = name;
            m_SingleText.setText(buff.toString());

            m_List.setSelectedValue(name, true);
        }
    }

    /**
     * To show the AUC
     *
     * @param name
     */
    public void setAuc(String name) {
        String temp = (String) m_HashAucs.get(name);
        if (temp != null) {
            this.m_AucLabel.setText("AUC(Area under the ROC curve): " + temp);
        }
    }

    public void setChart(String name) {
        ChartPanel temp = (ChartPanel) m_HashCharts.get(name);
        if (temp != null) {
            temp.setVisible(true);
            this.m_CurvePanel.removeAll();
            this.m_CurvePanel.add(temp);
            this.m_CurvePanel.validate();
            this.m_CurvePanel.repaint();
        }
    }

    public void setClassPanel(String[] classNames){
        for(int i=0;i<classNames.length;i++){
            //m_ClassPanel.add();
        }
    }

    /**
     * Opens the named result in a separate frame.
     *
     * @param name the name of the result to open.
     */
    public void openFrame(String name) {

        StringBuffer buff = (StringBuffer) m_HashResults.get(name);
        JTextComponent currentText = (JTextComponent) m_HashFramedOutput.get(name);
        if ((buff != null) && (currentText == null)) {
            // Open the frame.
            JTextArea ta = new JTextArea();
            ta.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
            ta.setFont(new Font("Monospaced", Font.PLAIN, 12));
            ta.setEditable(false);
            ta.setText(buff.toString());
            m_HashFramedOutput.put(name, ta);
            final JFrame jf = new JFrame(name);
            jf.addWindowListener(new WindowAdapter() {

                @Override
                public void windowClosing(WindowEvent e) {
                    m_HashFramedOutput.remove(jf.getTitle());
                    jf.dispose();
                }
            });
            jf.getContentPane().setLayout(new BorderLayout());
            jf.getContentPane().add(new JScrollPane(ta), BorderLayout.CENTER);
            jf.pack();
            jf.setSize(450, 350);
            jf.setVisible(true);
        }
    }

    /**
     * Tells any component currently displaying the named result that the
     * contents of the result text in the StringBuffer have been updated.
     *
     * @param name the name of the result that has been updated.
     */
    public void updateResult(String name) {

        StringBuffer buff = (StringBuffer) m_HashResults.get(name);
        if (buff == null) {
            return;
        }
        if (m_SingleName.equals(name)) {
            m_SingleText.setText(buff.toString());
        }
        JTextComponent currentText = (JTextComponent) m_HashFramedOutput.get(name);
        if (currentText != null) {
            currentText.setText(buff.toString());
        }
    }

    /**
     * Gets the selection model used by the results list.
     *
     * @return a value of type 'ListSelectionModel'
     */
    public ListSelectionModel getSelectionModel() {

        return m_List.getSelectionModel();
    }

    /**
     * Gets the JList used by the results list
     * @return the JList
     */
    public JList getList() {
        return m_List;
    }

    /**
     * Get the text panel
     * @return
     */
    public JTextComponent getText() {
        return this.m_SingleText;
    }

    public JButton getDetailButton() {
        return this.m_DetailButton;
    }

    /**
     * Get the auc label
     * @return
     */
    public JLabel getAucLabel() {
        return this.m_AucLabel;
    }

    /**
     * Get the curve panel
     * @return
     */
    public JPanel getCurvePanel() {
        return this.m_CurvePanel;
    }

    /**
     * Set whether the result history list should handle right clicks
     * or whether the parent object will handle them.
     * @param tf false if parent object will handle right clicks
     */
    public void setHandleRightClicks(boolean tf) {
        m_HandleRightClicks = tf;
    }

    /**
     * Tests out the result history from the command line.
     *
     * @param args ignored
     */
    public static void main(String[] args) {

        try {
            final javax.swing.JFrame jf =
                    new javax.swing.JFrame("Weka Explorer: Classifier");
            jf.getContentPane().setLayout(new BorderLayout());
            final ResultHistoryPanel jd = new ResultHistoryPanel(null);
            jd.addResult("blah", new StringBuffer("Nothing to see here"));
            jd.addResult("blah1", new StringBuffer("Nothing to see here1"));
            jd.addResult("blah2", new StringBuffer("Nothing to see here2"));
            jd.addResult("blah3", new StringBuffer("Nothing to see here3"));
            jf.getContentPane().add(jd, BorderLayout.CENTER);
            jf.addWindowListener(new java.awt.event.WindowAdapter() {

                @Override
                public void windowClosing(java.awt.event.WindowEvent e) {
                    jf.dispose();
                    System.exit(0);
                }
            });
            jf.pack();
            jf.setVisible(true);
        } catch (Exception ex) {
            ex.printStackTrace();
            System.err.println(ex.getMessage());
        }
    }
}
